/* Includes ------------------------------------------------------------------*/
#include <main.h>

/* Private define-------------------------------------------------------------*/
#define S1_S0 BIT6      //定义串口切换寄存器AUXR1的第6位
#define S1_S1 BIT7      //定义串口切换寄存器AUXR1的第7位

#define UART1_MAX485_DE_nRE   P20           //定义模式控制引脚
#define UART1_MAX485_SendMode   (bit)1      //RS-485设置为发送模式
#define UART1_MAX485_RecMode    (bit)0      //RS-485设置为接收模式

#define UART1_Send_LENGTH 10
#define UART1_Rec_LENGTH  10
/* Private variables----------------------------------------------------------*/
static uint8_t idata ucSend_Buffer[UART1_Rec_LENGTH]  = {0};
static uint8_t idata ucRec_Buffer[UART1_Rec_LENGTH]   = {0x00};
/* Private function prototypes------------------------------------------------*/
static void Init();                                 //串口初始化
static void SendData(uint8_t );                     //串口发送字符
static void SendArray(uint8_t *,uint16_t );         //串口发送数组
static void SendString(uint8_t *);                  //串口发送字符串
static void Protocol();                             //串口协议

static void RS485_Set_SendMode();                   //RS-485设置为发送模式
static void RS485_Set_RecMode();                    //RS-485设置为接收模式

/* Public variables-----------------------------------------------------------*/
UART_t idata UART1 = 
{
  Band_9600,
  FALSE,
  FALSE,
  0,

  ucSend_Buffer,
  ucRec_Buffer,

  Init,
  SendData,
  SendArray,
  SendString,
  Protocol,

  RS_485,
  RS485_Set_SendMode,
  RS485_Set_RecMode
};

/*
* @name   Init
* @brief  串口1初始化
* @param  None
* @retval None   
*/
static void Init()
{
  //把串口1映射到USB转TTL模块连接的P30和P31引脚，默认该两位是0
  #ifdef Monitor_Run_Code
    AUXR1  &= ~(S1_S1);         //AUXR1第7位清0
    AUXR1  &= ~(S1_S0);         //AUXR1第6位清0
  #endif

  //把串口1映射到RS-485连接到的P37和P36引脚
  #ifndef Monitor_Run_Code
    AUXR1 &= ~S1_S1;        //AUXR1第7位清0
    AUXR1 |=  S1_S0;        //AUXR1第6位置1
  #endif

  SCON = 0x50;		//8位数据,可变波特率,REN位置1，开启中断
  //辅助寄存器AUXR的第6位T1x12置1，设置定时器1的速度是传统8051的12倍，不分频
	AUXR |= 0x40;
  //1111 1110 最低位S1ST2清0，选择定时器1作为串口1的波特率发生器
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
  
	TMOD &= 0x0F;		//设定定时器1为16位自动重装方式
	switch (UART1.ucBandRate)
  {
    case Band_4800:   TL1 = 0xCD; TH1 = 0xFD; break;
    case Band_9600:   TL1 = 0xE0; TH1 = 0xFE; break;
    case Band_19200:  TL1 = 0x70; TH1 = 0xFF; break;
    case Band_115200: TL1 = 0xE8; TH1 = 0xFF; break;
    default:          TL1 = 0xCD; TH1 = 0xFD; break;
  }
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
  REN = 1;     //允许串口1接收
}

/*
* @name   SendData
* @brief  发送字符
* @param  dat：待发送的数据
* @retval None   
*/
static void SendData(uint8_t dat)
{
  while(UART1.ucTX_Busy_Flag);    //等待前面的数据发送完，串口中断中发送数据后标志位会置FALSE
  UART1.ucTX_Busy_Flag = TRUE;    //置为忙碌标志位
  SBUF = dat;                     //写数据到UART寄存器
}

/*
* @name   SendArray
* @brief  发送数组
* @param  p_Arr：数组首地址，LEN：发送长度
* @retval None   
*/
static void SendArray(uint8_t *p_Arr,uint16_t LEN)
{
  uint16_t i = 0;

  UART1.RS485_Set_SendMode();   //RS-485设置为发送模式

  for(i = 0;i<LEN;i++)
  {
    UART1.UART_SendData(*(p_Arr+i));
  }
  while(UART1.ucTX_Busy_Flag);   //等待数据发送完
  Public.Delay_ms(1);            //等待RS-485数据传输完
  
  UART1.RS485_Set_RecMode();    //让RS-485切回到接收模式，默认处于接收模式
}

/*
* @name   SendString
* @brief  发送字符串
* @param  p_Arr：字符串首地址
* @retval None   
*/
static void SendString(uint8_t *p_Str)
{
  UART1.RS485_Set_SendMode();     //RS-485设置为发送模式

  while(*(p_Str) != '\0')
  {
    UART1.UART_SendData(*(p_Str++));
  }
  while(UART1.ucTX_Busy_Flag);
  Public.Delay_ms(1);             //等待RS-485数据传输完

  UART1.RS485_Set_RecMode();      //RS-485设置为接收模式

}

/*
* @name   RS485_Set_SendMode
* @brief  RS_485接口设置为发送模式
* @param  None
* @retval None   
*/
static void RS485_Set_SendMode()
{
  //485模式控制引脚置1，设置为发送模式
  UART1_MAX485_DE_nRE = UART1_MAX485_SendMode;
  //延时一会，待硬件稳定
  Public.Delay_ms(1);
}

/*
* @name   RS485_Set_RecMode
* @brief  RS_485接口设置为接收模式
* @param  None
* @retval None   
*/
static void RS485_Set_RecMode()
{
  //延时一会，待硬件稳定
  Public.Delay_ms(1);
  //485模式控制引脚清0，设置为接收模式
  UART1_MAX485_DE_nRE = UART1_MAX485_RecMode;
  
}

/*
* @name   putchar
* @brief  字符发送函数重定向
* @param  ch：发送的字符
* @retval char   
*/
#ifdef Monitor_Run_Code
  extern char putchar(char ch)
  {
    UART1.UART_SendData((uint8_t)ch);   //在putchar函数内直接调用串口发送字符函数
    return ch;
  }
#endif

/*
* @name   UART1_isr
* @brief  串口1中断处理函数
* @param  None
* @retval None   
*/
void UART1_isr() interrupt 4
{
  if(RI)
  {
    RI = (bit)0;                   //清除接收中断标志
    /*UART1_Rec_LENGTH宏定义为10，所以接收的数据不能超过10个字节
    UART1.ucRec_Cnt表示数组下标，初始化为0*/
    if(UART1.ucRec_Cnt < UART1_Rec_LENGTH)
    {
      ucRec_Buffer[UART1.ucRec_Cnt++] = SBUF;
    }
    UART1.ucRec_Flag = TRUE;      //接收完成标志位
  }

  if(TI)
  {
    TI = (bit)0;                    //清除发送中断标志
    UART1.ucTX_Busy_Flag = FALSE;   //清除忙碌标志
  }
}

/*
* @name   Protocol
* @brief  串口协议
* @param  None
* @retval None   
*/
static void Protocol()
{
  //判断经过RS-485传输后串口是否接收到数据
  if(UART1.ucRec_Flag == TRUE)
  {
    //过滤干扰数据0
    //Modbus协议中，主机发送的信息帧第一个字节是从机地址，范围是1 ~ 247，该if语句则判断是否是从机地址，0是广播地址
    if(ucRec_Buffer[0] != 0)
    {
      Timer0.usDelay_Timer = 0; //延时定时器清零，开始计时
      while(UART1.ucRec_Cnt < 8)
      {
        //喂狗
        WatchDog.Feed();
        
       if(Timer0.usDelay_Timer >= TIMER_100MS) //100ms内没接收完8个字节，则跳出循环
       {
         break;
       }
      }
      //接收完8个字节数据，则进行协议分析
      Modbus.Protocol_Analysis(&UART1);
    }
    //清除缓存
    Public.Memory_Clr(ucRec_Buffer,(uint16_t)UART1.ucRec_Cnt);

    //重新接收
    UART1.ucRec_Cnt = 0;
    UART1.ucRec_Flag = FALSE;
  }
}
/********************************************************
  End Of File
********************************************************/